package cn.jiedanba.itext5.check;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.x509.CRLDistPoint;
import org.bouncycastle.asn1.x509.DistributionPoint;
import org.bouncycastle.cert.X509CertificateHolder;

/**
 * 使用CRL检查证书状态
 */
public class CRLCheck {

	private X509Certificate cert;

	public CRLCheck() {

	}

	public CRLCheck(X509Certificate cert) {
		this.cert = cert;
	}

	/**
	 * 检查证书是否有效
	 * 
	 * @return true：有效 false：无效
	 */
	public boolean checkCertStatus() {
		try {
			String crlUrl = getCrlUrl(cert);
			if (crlUrl == null) {
				throw new IllegalArgumentException("证书无CRL吊销列表");
			}
			URL url = new URL(crlUrl);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			int responseCode = connection.getResponseCode();
			if (responseCode != HttpURLConnection.HTTP_OK) {
				throw new RuntimeException("CRL下载出错");
			}
			InputStream inputStream = connection.getInputStream();

			ByteArrayOutputStream output = new ByteArrayOutputStream();
			byte[] buffer = new byte[4096];
			int bytesRead;
			while ((bytesRead = inputStream.read(buffer)) != -1) {
				output.write(buffer, 0, bytesRead);
			}

			inputStream.close();
			connection.disconnect();
			byte[] crlData = output.toByteArray();
			InputStream in = new ByteArrayInputStream(crlData);
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509CRL crl = (X509CRL) cf.generateCRL(in);
			in.close();
			if (isRevoked(crl, cert) != null) {
				return false;
			}
			return true;
		} catch (Exception e) {
			throw new RuntimeException("CRL检查出错", e);
		}
	}

	/**
	 * 从证书中获取Crl URL
	 * 
	 * @param certificate
	 * @return
	 * @throws IOException
	 */
	private String getCrlUrl(X509Certificate certificate) throws IOException {
		try {
			// 解析X.509证书
			X509CertificateHolder certHolder = new X509CertificateHolder(certificate.getEncoded());
			String url = null;
			// 获取CRL分发点
			CRLDistPoint crlDistPoint = CRLDistPoint.fromExtensions(certHolder.getExtensions());
			if (crlDistPoint != null) {
				DistributionPoint[] distPoints = crlDistPoint.getDistributionPoints();
				for (DistributionPoint distPoint : distPoints) {
					ASN1Encodable generalNames = distPoint.getDistributionPoint().getName();
					url = generalNames.toString().replaceAll("GeneralNames:", "").replaceAll("6:", "").trim();
					break;
				}
			}
			return url;
		} catch (Exception e) {
			throw new RuntimeException("从证书中获取CRL URL出错", e);
		}

	}

	/**
	 * 验证证书是否在CRL中。
	 * 
	 * @param X509CRL         crl对象
	 * @param X509Certificate 证书对象
	 * @throws IOException
	 */
	private X509CRLEntry isRevoked(X509CRL crl, X509Certificate cert) throws IOException {
		BigInteger sn = cert.getSerialNumber();
		X509CRLEntry set = crl.getRevokedCertificate(sn);
		if (set != null) {
			return set;
		} else {
			return null;
		}
	}
}
